/**
 * Copyright 2018 orivil.com. All rights reserved.
 * Use of this source code is governed by a MIT-style
 * license that can be found at https://mit-license.org.
 */

package material

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/tugoer/orivil/wechat"
	"io"
	"io/ioutil"
	"mime/multipart"
	"net/http"
	"net/url"
)

var ErrVideoDescriptionIsNil = errors.New(`视频素材需要上传描述信息, 字段名称: "description", 数据类型: "json", 数据模型: {"title":VIDEO_TITLE, "introduction":INTRODUCTION}`)

type Response struct {
	wechat.Error
	Result
}

type Result struct {
	MediaID string `json:"media_id" desc:"新增的永久素材的media_id"`
	Url     string `json:"url" desc:"新增的图片素材的图片URL（仅新增图片素材时会返回该字段）"`
}

type VideoDescription struct {
	Title        string `json:"title"`
	Introduction string `json:"introduction"`
}

// 上传一个或多个永久素材
func UploadMaterial(req *http.Request, kind media, token string) (results []*Result, err error) {
	err = req.ParseMultipartForm(0)
	if err != nil {
		return nil, err
	}
	var description string

	if kind == VIDEO {
		// 检查视频描述信息, https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1444738729
		vs := url.Values(req.MultipartForm.Value)
		description = vs.Get("description")
		if description == "" {
			return nil, ErrVideoDescriptionIsNil
		}
		desc := &VideoDescription{}
		err := json.Unmarshal([]byte(description), desc)
		if err != nil {
			return nil, fmt.Errorf("解析视频描述时出错: %s", err)
		}
	}
	for _, headers := range req.MultipartForm.File {
		for _, header := range headers {
			f, err := header.Open()
			if err != nil {
				return nil, err
			}
			result, err := func() (result *Result, err error) {
				defer f.Close()
				buf := &bytes.Buffer{}
				mulWriter := multipart.NewWriter(buf)
				fileWriter, err := mulWriter.CreateFormFile("media", header.Filename)
				if err != nil {
					return nil, err
				}
				_, err = io.Copy(fileWriter, f)
				if err != nil {
					return nil, err
				}

				if kind == VIDEO {
					// 添加视频描述信息
					partWriter, err := mulWriter.CreateFormField("description")
					if err != nil {
						return nil, err
					} else {
						_, err = partWriter.Write([]byte(description))
						if err != nil {
							return nil, err
						}
					}
				}

				contentType := mulWriter.FormDataContentType()
				mulWriter.Close()
				ul := "https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=" + token + "&type=" + string(kind)
				resp, err := http.Post(ul, contentType, buf)
				if err != nil {
					return nil, err
				}
				defer resp.Body.Close()
				data, err := ioutil.ReadAll(resp.Body)
				if err != nil {
					return nil, err
				}
				res := &Response{}
				err = json.Unmarshal(data, res)
				if err != nil {
					return nil, err
				}
				if res.ErrCode != 0 {
					return nil, res.Error
				} else {
					return &res.Result, nil
				}
			}()
			if err != nil {
				return nil, err
			} else {
				results = append(results, result)
			}
		}
	}
	return results, nil
}

type News struct {
	Articles []*Article
}

type Article struct {
	Title            string `json:"title" desc:"标题"`
	ThumbMediaID     string `json:"thumb_media_id" desc:"图文消息的封面图片素材id（必须是永久mediaID）"`
	Author           string `json:"author" desc:"作者"`
	Digest           string `json:"digest" desc:"图文消息的摘要，仅有单图文消息才有摘要，多图文此处为空。如果本字段为没有填写，则默认抓取正文前64个字。"`
	ShowCoverPic     string `json:"show_cover_pic" desc:"是否显示封面，0为false，即不显示，1为true，即显示"`
	Content          string `json:"content" desc:"图文消息的具体内容，支持HTML标签，必须少于2万字符，小于1M，且此处会去除JS,涉及图片url必须来源 '上传图文消息内的图片获取URL'接口获取。外部图片url将被过滤。"`
	ContentSourceUrl string `json:"content_source_url" desc:"图文消息的原文地址，即点击“阅读原文”后的URL"`
	Url string `json:"url" desc:"上传图文之后该图文会有一个 Url 地址"`
}

// 上传图文
func UploadNews(news *News, token string) (result *Result, err error) {
	ul := "https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=" + token
	err = wechat.PostJson(ul, news, &result)
	return
}

func DelMaterial(mediaID, token string) error {
	ul := "https://api.weixin.qq.com/cgi-bin/material/del_material?access_token=" + token
	return wechat.PostJson(ul, map[string]string{"media_id": mediaID}, nil)
}
//
//func GetMaterial(mediaID, token string)  {
//
//}

type Count struct {
	Voice int `json:"voice_count"`
	Video int `json:"video_count"`
	Image int `json:"image_count"`
	News  int `json:"news_count"`
}

// 获得素材统计
func CountMaterials(token string) (count *Count, err error) {
	resp, err := http.Get("https://api.weixin.qq.com/cgi-bin/material/get_materialcount?access_token=" + token)
	if err != nil {
		return nil, err
	} else {
		defer resp.Body.Close()
		count = &Count{}
		err = json.NewDecoder(resp.Body).Decode(count)
		if err != nil {
			return nil, err
		} else {
			return count, err
		}
	}
}

type getList struct {
	Type   string `json:"type"`
	Offset int    `json:"offset"`
	Count  int    `json:"count"`
}

type NewsList struct {
	TotalCount int `json:"total_count"`
	ItemCount int `json:"item_count"`
	Item []NewItem `json:"item"`
	wechat.Error
}

type MediaList struct {
	TotalCount int `json:"total_count"`
	ItemCount int `json:"item_count"`
	Item []Media `json:"item"`
	wechat.Error
}

type Media struct {
	MediaID string `json:"media_id"`
	Name string `json:"name"`
	UpdateTime uint64 `json:"update_time"`
	Url string `json:"url"`
}

type NewItem struct {
	MediaID string `json:"media_id"`
	Content Content `json:"content"`
	UpdateTime int64 `json:"update_time"`
}

type Content struct {
	NewsItem []Article `json:"news_item"`
}

// 获得素材列表
func GetMedias(kind media, token string, limit, offset int) (res *MediaList, err error) {
	ul := "https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=" + token
	err = wechat.PostJson(ul, map[string]interface{}{
		"type": kind,
		"offset": offset,
		"count": limit,
	}, &res)
	return
}

// 获得图文列表
func GetNews(token string, limit, offset int) (res *NewsList, err error) {
	ul := "https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=" + token
	err = wechat.PostJson(ul, map[string]interface{}{
		"type": NEWS,
		"offset": offset,
		"count": limit,
	}, &res)
	return
}
